package server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import javax.net.ssl.SSLSocket;


public class Server {
	private static int PORT  = 4444;
	public final static int NEW = 2;
	public final static int DELETE = 3;
	public final static int OPEN = 4;
	public final static int SAVE = 5;
	public final static int NULL = 0;
	public final static int OK = 1;

	private String currentFile = "";
	private Database database = new Database();
	private BufferedReader bufferedreader;
	private PrintWriter outputstream;
	private String username = "";
	private String rank = "";
	private String division = "";
	private Logger log;
	public static void main(String[] args){	
		new Server();
	}

	public Server(){		
		while(true){
			Session session = new Session(PORT).doIt();
			String subject = session.getSubject();
			SSLSocket socket  = session.getSocket();


			String[] first = subject.split(", ");
			username = first[0].substring(3,first[0].length());
			rank = first[1].substring(3,first[1].length());
			division = first[2].substring(2,first[2].length());

			log = new Logger(username, rank, division);

			try{
				bufferedreader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				outputstream =  new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
				sendReadableFiles();
				outputstream.flush();
				//while client does not close the socket
				while(!socket.isClosed()){
					String text = waitForCommand();
					System.out.println(text);
					int command = Integer.parseInt(text.substring(0,1));
					if(!faultCheck(command, text)){
						outputstream.write(NULL+"\n");
						System.out.println("NULL1");
					}					
					text = text.substring(1, text.length());					
					if(!accessControl(command, text)){
						//while (!bufferedreader.readLine().equals("EOF"))
						outputstream.write(NULL+"\n");
						outputstream.flush();
						System.out.println("NULL2");
					}else{
						doCommand(command,text);						
					}
				}
				outputstream.close();
				bufferedreader.close();
			}catch(Exception e){
				e.printStackTrace();
			}		

		}


	}
	/**
	 * Here the server does the command provided by the client.
	 * @param text 
	 * @param command
	 */
	private void doCommand(int command, String text) {		
		String fileName = currentFile;
		boolean packageOK = true;
		switch(command){
		case NEW: //saves a new file to the database.
			String[] splitted = text.split("::");
			String[] info = null;
			// if the text is null for some reason.. send null otherwise
			if(splitted[0] == null || splitted[1] == null){
				outputstream.write(OK+"\n");
				sendReadableFiles(); 
			    outputstream.write(NULL+"\n");
		     	outputstream.println("EOF");
		     	packageOK = false;
				break;
			}
			//if both the patient and the nurse exists
			if(database.containsUser(splitted[0]) && database.containsUser(splitted[1])){
				info = database.addNewFileToUser(username, division,splitted[0], splitted[1]);
				System.out.println("Ny fil");
				outputstream.write(OK+"\n");
				sendReadableFiles(); 
				outputstream.write(info[1] + "\n");
				outputstream.println("EOF");
				currentFile = info[0];
				fileName = info[0];
			}else{ //send null otherwise
				outputstream.write(OK+"\n");
				sendReadableFiles(); 
				outputstream.write(NULL+"\n");
				outputstream.println("EOF");
				packageOK = false;
			}
			break;
		case SAVE: //saves an edited file to the database, can only happen after the open command.
			String temp = "";
			text = "";
			try {
				while (!(temp = bufferedreader.readLine()).equals("EOF")) {
					text += temp + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(text);

			if(!database.addFileToUser(username, division , currentFile, text)){
				outputstream.println(-1);
				packageOK = false;
				
			}else{
				outputstream.write(OK +"\n");
				System.out.println("Skickade OK");
			}
			break;
		case DELETE: //delete file from database
			database.removeFile(text);
			outputstream.write(OK+"\n");
			outputstream.println(database.getAllFilesForFBI());
			System.out.println("Deletade");
			fileName = text;
			break;
		case OPEN: //write the database file to the outputstream.
			currentFile = text;
			fileName = currentFile;
			outputstream.write(OK+"\n");
			outputstream.write(database.getFileFromUser(username, currentFile, division)+"\n");
			outputstream.println("EOF");
			System.out.println("Öppnat");
			break;
		default: outputstream.write(NULL); break;

		}
		outputstream.flush();
		log.log(command, fileName, true, packageOK);
	}
	/**
	 * Checks if the subject can do a certain command.
	 * @param command the command to be used on server side
	 * @param text 
	 * @return false or true depending if the subject has access
	 */
	private boolean accessControl(int command, String text) {
		System.out.println(rank + "command: " + command);
		boolean accessOK = false;
		String fileName = currentFile;
		switch(command){
		case NEW:
			fileName = "";
			System.out.println(rank);
			accessOK =  "Doktor".equalsIgnoreCase(rank);
			break;
		case SAVE: 
			if("Patient".equalsIgnoreCase(rank))
				accessOK = false;
			else if("Gov".equalsIgnoreCase(rank))
				accessOK = false;
			else
				return database.getListOfWritableFiles(username).contains(currentFile);	
			break;
		case DELETE: 
			accessOK =  "Gov".equalsIgnoreCase(rank);
			fileName = text;
			break;
		case OPEN:			
			if("Gov".equalsIgnoreCase(rank))
				accessOK =  true;
			else 
				accessOK =  database.getListOfAllFiles(division,username).contains(fileName);
			break;
		}
		System.out.println("ACCESSCONTROLZ: " + accessOK + " rank: " + rank);
		if(!accessOK)
			log.log(command, fileName, false, true);

		return accessOK;
	}
	/**
	 * Waits for commands from client, a command, integer, followed by a string which
	 * represents a journal or a text file.
	 * @return
	 */
	private String waitForCommand() {
		String text = "0";
		try {
			System.out.println("Väntar på command");
			text = bufferedreader.readLine();
			System.out.println("Tog emot: " + text);
		} catch (IOException e) {
			System.out.println("I/O Exception in method waitForCommand");
		}

		return text;   
	}
	private boolean faultCheck(int command, String text){
		if(command == SAVE) //SAVE är en slamkrypare
			return true;
		if(text.length()>1 && command >0 && command <6){
			return true;
		}else{
			log.log(0, "", false, false);
		}
		return false;

	}
	/**
	 * Sends the readable files
	 * 
	 */
	private void sendReadableFiles(){
		if(rank.equalsIgnoreCase("Gov"))
			outputstream.write(database.getAllFilesForFBI()+"\n");
		else 
			outputstream.write(database.getListOfAllFiles(division, username)+"\n");
	}



}
